#include "MFD.hpp"
#include "config.hpp"
#include <cstddef>
#include <iomanip>
#include <iostream>
#include <limits>
#include <string>

bool MFD::login(std::string user_name) {
  MF *current = MF_list;
  while (current) {
    if (current->user_name == user_name) {
      current_user = current;
      return true;
    }
    current = current->next_MF;
  }
  std::cout << "Your name is not in the user name table, try again."
            << std::endl;
  return false;
}

void MFD::create(std::string file_name, short int protect_code, size_t length) {
  if (!current_user) {
    std::cout << "No user logged in!" << std::endl;
    return;
  }
  UF *new_file = new UF(file_name, protect_code, length, current_user->UF_list);
  current_user->UF_list = new_file;
  std::cout << "The new file is created." << std::endl;
}

void MFD::deleteFile(std::string file_name) {
  if (!current_user) {
    std::cout << "No user logged in!" << std::endl;
    return;
  }
  current_user->deleteFile(file_name);
}

void MFD::open(std::string file_name, short int mode) {
  if (!current_user) {
    std::cout << "No user logged in!" << std::endl;
    return;
  }

  if (opened) {
    std::cout << "Error: More than 1 opened file!\n";
    return;
  }

  UF *file = current_user->findFile(file_name);
  if (file) {
    opened = file;
    open_mode = mode; // Set protection level when opening
    std::cout << "This file is opened." << std::endl;
  } else {
    std::cout << "File not found!" << std::endl;
  }
}

void MFD::close(std::string file_name) {
  if (!current_user) {
    std::cout << "No user logged in!" << std::endl;
    return;
  }

  UF *file = current_user->findFile(file_name);
  if (file && file == opened) {
    std::cout << "This file is closed." << std::endl;
    opened = nullptr;
  } else {
    std::cout << "File not found!" << std::endl;
  }
}

void MFD::read(std::string file_name) {
  if (!current_user) {
    std::cout << "No user logged in!" << std::endl;
    return;
  }

  UF *file = current_user->findFile(file_name);

  if (file) {
    if (file != opened) {
      std::cout << "Error: This file is not opened!" << std::endl;
    } else if ((file->file_model.protect_code / 10) % 10 != 1 ||
               (open_mode / 10) % 10 != 1) {
      std::cout << "Error: It is not allowed to read this file!" << std::endl;
    } else {
      std::cout << "Reading file: " << file_name << std::endl;
    }
  } else {
    std::cout << "File not found!" << std::endl;
  }
}

void MFD::write(std::string file_name, size_t length) {
  if (!current_user) {
    std::cout << "No user logged in!" << std::endl;
    return;
  }

  UF *file = current_user->findFile(file_name);
  if (file) {
    if (file != opened) {
      std::cout << "Error: This file is not opened!" << std::endl;
    } else if (file->file_model.protect_code / 100 != 1 ||
               open_mode / 100 != 1) {
      std::cout << "Error: It is not allowed to write this file!" << std::endl;
    } else {
      file->file_model.length += length;
      std::cout << "Written " << length << " characters to the file."
                << std::endl;
    }
  } else {
    std::cout << "File not found!" << std::endl;
  }
}

void MFD::showUserFiles() {
  if (!current_user) {
    std::cout << "No user logged in!" << std::endl;
    return;
  }

  UF *current = current_user->UF_list;
  std::cout << "YOUR FILE DIRECTORY:" << std::endl;
  while (current) {
    std::cout << current->file_model.name << " " << std::setfill('0')
              << std::setw(3) << current->file_model.protect_code << " "
              << current->file_model.length;
    if (opened == current) {
      std::cout << " opened";
    }
    std::cout << std::endl;
    current = current->next_UF;
  }
}

void MFD::logout() {
  if (current_user) {
    std::cout << "Goodbye " << current_user->user_name << "." << std::endl;
    current_user = nullptr;
  } else {
    std::cout << "No user logged in!" << std::endl;
  }
}

void MFD::commandLoop() {
  std::string command;
  while (true) {
    showUserFiles();
    std::cout << "COMMAND NAME? ";
    std::getline(std::cin, command);

    if (command == "create") {
      std::string file_name;
      short int protect_code;
      size_t length;
      std::cout << "The new file's name? ";
      std::getline(std::cin, file_name);
      std::cout << "The new file's protection code? ";
      std::cin >> protect_code;
      std::cout << "The new file's length? ";
      std::cin >> length;
      create(file_name, protect_code, length);
      std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    } else if (command == "delete") {
      std::string file_name;
      std::cout << "File name to delete? ";
      std::getline(std::cin, file_name);
      deleteFile(file_name);
    } else if (command == "open") {
      std::string file_name;
      short int mode;
      std::cout << "File name to open? ";
      std::getline(std::cin, file_name);
      std::cout << "Enter the open mode? ";
      std::cin >> mode;
      open(file_name, mode);
      std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    } else if (command == "close") {
      std::string file_name;
      std::cout << "File name to close? ";
      std::getline(std::cin, file_name);
      close(file_name);
    } else if (command == "read") {
      std::string file_name;
      std::cout << "File name to read? ";
      std::getline(std::cin, file_name);
      read(file_name);
    } else if (command == "write") {
      std::string file_name;
      size_t length;
      std::cout << "File name to write to? ";
      std::getline(std::cin, file_name);
      std::cout << "How many characters to write? ";
      std::cin >> length;
      write(file_name, length);
      std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    } else if (command == "bye") {
      logout();
      break; // Exit the command loop and log out
    } else {
      std::cout << "Unknown command, please try again." << std::endl;
    }
  }
}

void MFD::userLoop() {
  std::string user_name;
  while (true) {
    std::cout << "YOUR NAME? ";
    std::getline(std::cin, user_name);
    if (!login(user_name)) {
      continue;
    }

    if (current_user) {
      int tmp[] = {1, 11, 111, 10, 101};
      for (int i = 0; i < N_FILE; ++i) {
        create(std::to_string(i + 1), tmp[i], 20);
      }
      commandLoop(); // Enter command loop for the logged-in user
    }

    // if (current_user) {
    //   break; // Exit user loop after logout
    // }
  }
}

void MFD::createUser(std::string user_name) {
  // Check if user already exists
  MF *current = MF_list;
  while (current) {
    if (current->user_name == user_name) {
      std::cout << "User already exists!" << std::endl;
      return;
    }
    current = current->next_MF;
  }

  // Create new user
  MF *new_user = new MF(user_name);
  new_user->next_MF = MF_list;
  MF_list = new_user;
  current_user = new_user;
  // std::cout << "User " << user_name << " created successfully." << std::endl;
}

// void MFD::commandLoop() { this->login(std::string user_name); }

// void MFD::operationLoop() {
//   std::string command;
//   while (true) {
//     std::cout << "COMMAND NAME? ";
//     std::getline(std::cin, command);

//     if (command == "create") {
//       std::string file_name;
//       short int protect_code;
//       size_t length;
//       std::cout << "The new file's name (less than 9 chars)? ";
//       std::getline(std::cin, file_name);
//       std::cout << "The new file's protection code? ";
//       std::cin >> protect_code;
//       std::cout << "The new file's length? ";
//       std::cin >> length;
//       create(file_name, protect_code, length);
//       std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
//     } else if (command == "delete") {
//       std::string file_name;
//       std::cout << "File name to delete? ";
//       std::getline(std::cin, file_name);
//       deleteFile(file_name);
//     } else if (command == "open") {
//       std::string file_name;
//       short int mode;
//       std::cout << "File name to open? ";
//       std::getline(std::cin, file_name);
//       std::cout << "Enter the open mode? ";
//       std::cin >> mode;
//       open(file_name, mode);
//       std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
//     } else if (command == "close") {
//       std::string file_name;
//       std::cout << "File name to close? ";
//       std::getline(std::cin, file_name);
//       close(file_name);
//     } else if (command == "read") {
//       std::string file_name;
//       std::cout << "File name to read? ";
//       std::getline(std::cin, file_name);
//       read(file_name);
//     } else if (command == "write") {
//       std::string file_name;
//       size_t length;
//       std::cout << "File name to write to? ";
//       std::getline(std::cin, file_name);
//       std::cout << "How many characters to write? ";
//       std::cin >> length;
//     }
//   }
// }